package com.zt.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zt.dto.CouponDistributionDto;
import com.zt.dto.UserQueryDto;
import com.zt.entity.Coupons;
import com.zt.entity.Result;
import com.zt.entity.UserCoupons;
import com.zt.entity.Users;
import com.zt.mapper.CouponsMapper;
import com.zt.mapper.UserCouponsMapper;
import com.zt.mapper.UsersMapper;
import com.zt.service.AdminLogService;
import com.zt.service.CouponDistributionService;
import com.zt.service.CouponDistributionCacheService;
import com.zt.util.CouponCacheUtil;
import com.zt.vo.CouponDistributionStatsVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 优惠券发放服务实现类
 */
@Service
@Slf4j
public class CouponDistributionServiceImpl implements CouponDistributionService {
    
    @Autowired
    private CouponsMapper couponsMapper;
    
    @Autowired
    private UsersMapper usersMapper;
    
    @Autowired
    private UserCouponsMapper userCouponsMapper;
    
    @Autowired
    private AdminLogService adminLogService;

    @Autowired
    private CouponDistributionCacheService distributionCacheService;

    @Autowired
    private CouponCacheUtil couponCacheUtil;
    
    @Override
    public List<Coupons> getActiveCoupons() {
        LambdaQueryWrapper<Coupons> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Coupons::getStatus, 1); // 1表示激活状态
        wrapper.orderByDesc(Coupons::getCreatedAt);
        return couponsMapper.selectList(wrapper);
    }
    
    @Override
    public IPage<Users> getUserList(UserQueryDto userQueryDto) {
        Page<Users> page = new Page<>(userQueryDto.getPageNum(), userQueryDto.getPageSize());
        LambdaQueryWrapper<Users> wrapper = new LambdaQueryWrapper<>();
        
        // 只查询未停用的用户
        wrapper.ne(Users::getStatus, 0);
        
        // 按手机号查询
        if (StringUtils.hasText(userQueryDto.getPhone())) {
            wrapper.like(Users::getPhone, userQueryDto.getPhone());
        }
        
        // 按昵称查询
        if (StringUtils.hasText(userQueryDto.getNickname())) {
            wrapper.like(Users::getNickname, userQueryDto.getNickname());
        }
        
        // 按状态查询
        if (userQueryDto.getStatus() != null) {
            wrapper.eq(Users::getStatus, userQueryDto.getStatus());
        }
        
        wrapper.orderByDesc(Users::getCreatedAt);
        return usersMapper.selectPage(page, wrapper);
    }
    
    @Override
    @Transactional
    public Result distributeCoupons(CouponDistributionDto distributionDto) {
        try {
            // 1. 验证优惠券是否存在且已激活
            Coupons coupon = couponsMapper.selectById(distributionDto.getCouponId());
            if (coupon == null) {
                return Result.error("优惠券不存在");
            }
            if (coupon.getStatus() != 1) {
                return Result.error("优惠券未激活，无法发放");
            }
            
            // 2. 获取要发放的用户列表
            List<Integer> userIds = distributionDto.getUserIds();
            if (userIds == null || userIds.isEmpty()) {
                return Result.error("请选择要发放的用户");
            }
            
            // 3. 检查优惠券发放限制
            Integer distributedCount = getCouponDistributedCount(distributionDto.getCouponId());
            if (coupon.getTotalCount() != null && 
                distributedCount + userIds.size() > coupon.getTotalCount()) {
                return Result.error("发放数量超过优惠券总数限制");
            }
            
            int successCount = 0;
            int skipCount = 0;
            List<UserCoupons> successfulDistributions = new ArrayList<>();

            // 4. 逐个发放优惠券
            for (Integer userId : userIds) {
                // 检查用户是否已经拥有该优惠券
                if (hasUserCoupon(userId, distributionDto.getCouponId())) {
                    skipCount++;
                    continue;
                }

                // 检查用户每人限领数量
                if (coupon.getLimitPerUser() != null) {
                    LambdaQueryWrapper<UserCoupons> limitWrapper = new LambdaQueryWrapper<>();
                    limitWrapper.eq(UserCoupons::getUserId, userId)
                              .eq(UserCoupons::getCouponId, distributionDto.getCouponId());
                    Long userCouponCount = userCouponsMapper.selectCount(limitWrapper);
                    if (userCouponCount >= coupon.getLimitPerUser()) {
                        skipCount++;
                        continue;
                    }
                }

                // 创建用户优惠券记录
                UserCoupons userCoupon = new UserCoupons();
                userCoupon.setUserId(userId);
                userCoupon.setCouponId(distributionDto.getCouponId());
                userCoupon.setStatus(1); // 1表示未使用
                userCoupon.setCreatedAt(new Date());

                userCouponsMapper.insert(userCoupon);
                successfulDistributions.add(userCoupon);
                successCount++;
            }

            // 4.1. 批量缓存成功发放的优惠券数据到Redis
            if (!successfulDistributions.isEmpty()) {
                try {
                    // 原有的缓存逻辑
                    distributionCacheService.batchCacheUserCoupons(successfulDistributions);
                    distributionCacheService.incrementCouponDistributedCount(distributionDto.getCouponId(), successCount);

                    // 新增：按指定格式缓存用户优惠券详细信息
                    for (UserCoupons userCoupon : successfulDistributions) {
                        try {
                            // 为每个用户添加优惠券到指定格式的缓存中
                            couponCacheUtil.addCouponToUserCache(userCoupon.getUserId().longValue(), coupon, 6);
                        } catch (Exception e) {
                            log.error("为用户 {} 缓存优惠券详细信息失败: {}", userCoupon.getUserId(), e.getMessage());
                        }
                    }

                    log.info("成功缓存优惠券发放数据到Redis: couponId={}, count={}", distributionDto.getCouponId(), successCount);
                } catch (Exception e) {
                    log.error("缓存优惠券发放数据到Redis失败: couponId={}", distributionDto.getCouponId(), e);
                    // 缓存失败不影响主流程，只记录日志
                }
            }
            
            // 5. 记录操作日志
            String logDescription = String.format("发放优惠券：%s，成功发放%d张，跳过%d张",
                coupon.getTitle(), successCount, skipCount);
            adminLogService.saveLog(null, "unknown", "优惠券管理", "发放", logDescription,
                "POST", "/admin/coupon-distribution/distribute", distributionDto.toString(),
                "发放成功", 1, null, "127.0.0.1", "System", 0L);
            
            return Result.success(String.format("发放完成！成功发放%d张，跳过%d张", successCount, skipCount));
            
        } catch (Exception e) {
            log.error("发放优惠券失败", e);
            adminLogService.saveLog(null, "unknown", "优惠券管理", "发放", "发放优惠券失败",
                "POST", "/admin/coupon-distribution/distribute", distributionDto.toString(),
                "发放失败：" + e.getMessage(), 0, e.getMessage(), "127.0.0.1", "System", 0L);
            return Result.error("发放失败：" + e.getMessage());
        }
    }
    
    @Override
    public boolean hasUserCoupon(Integer userId, Integer couponId) {
        // 先从缓存查询
        Boolean cachedResult = distributionCacheService.hasUserCouponFromCache(userId, couponId);
        if (cachedResult != null) {
            return cachedResult;
        }

        // 缓存未命中，从数据库查询
        LambdaQueryWrapper<UserCoupons> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupons::getUserId, userId)
               .eq(UserCoupons::getCouponId, couponId);
        boolean hasUserCoupon = userCouponsMapper.selectCount(wrapper) > 0;

        // 将结果缓存（通过创建一个临时的UserCoupons对象来缓存）
        if (hasUserCoupon) {
            UserCoupons tempUserCoupon = new UserCoupons();
            tempUserCoupon.setUserId(userId);
            tempUserCoupon.setCouponId(couponId);
            distributionCacheService.cacheUserCoupon(tempUserCoupon);
        }

        return hasUserCoupon;
    }
    
    @Override
    public Integer getCouponDistributedCount(Integer couponId) {
        // 先从缓存查询
        Integer cachedCount = distributionCacheService.getCouponDistributedCountFromCache(couponId);
        if (cachedCount != null) {
            return cachedCount;
        }

        // 缓存未命中，从数据库查询
        LambdaQueryWrapper<UserCoupons> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupons::getCouponId, couponId);
        Integer count = Math.toIntExact(userCouponsMapper.selectCount(wrapper));

        // 将结果缓存
        distributionCacheService.incrementCouponDistributedCount(couponId, count);

        return count;
    }

    @Override
    public CouponDistributionStatsVO getCouponDistributionStats(Integer couponId) {
        // 先从缓存获取
        CouponDistributionStatsVO cachedStats = distributionCacheService.getCouponDistributionStatsFromCache(couponId);
        if (cachedStats != null) {
            return cachedStats;
        }

        // 缓存未命中，从数据库查询
        Coupons coupon = couponsMapper.selectById(couponId);
        if (coupon == null) {
            return null;
        }

        CouponDistributionStatsVO stats = new CouponDistributionStatsVO();
        stats.setCouponId(couponId);
        stats.setCouponTitle(coupon.getTitle());
        stats.setTotalCount(coupon.getTotalCount());

        // 查询发放统计
        LambdaQueryWrapper<UserCoupons> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupons::getCouponId, couponId);

        // 总发放数量
        Integer distributedCount = Math.toIntExact(userCouponsMapper.selectCount(wrapper));
        stats.setDistributedCount(distributedCount);

        // 已使用数量
        wrapper.eq(UserCoupons::getStatus, 2); // 2表示已使用
        Integer usedCount = Math.toIntExact(userCouponsMapper.selectCount(wrapper));
        stats.setUsedCount(usedCount);

        // 未使用数量
        stats.setUnusedCount(distributedCount - usedCount);

        // 计算各种比率
        stats.calculateAllRates();

        // 缓存统计结果
        distributionCacheService.cacheCouponDistributionStats(couponId, stats);

        return stats;
    }

    @Override
    public Result giveNewUserCoupon(Long userId, Integer defaultCouponId) {
        try {
            // 1. 获取指定ID的优惠券
            Coupons coupon = couponsMapper.selectById(defaultCouponId);
            if (coupon == null) {
                log.warn("默认优惠券不存在，ID: {}", defaultCouponId);
                return Result.error("默认优惠券不存在");
            }

            // 2. 检查优惠券是否已激活
            if (coupon.getStatus() != 1) {
                log.warn("默认优惠券未激活，ID: {}", defaultCouponId);
                return Result.error("默认优惠券未激活");
            }

            // 3. 检查用户是否已经拥有该优惠券
            if (hasUserCoupon(userId.intValue(), defaultCouponId)) {
                log.info("用户 {} 已拥有优惠券 {}，跳过发放", userId, defaultCouponId);
                return Result.success("用户已拥有该优惠券");
            }

            // 4. 创建用户优惠券记录
            UserCoupons userCoupon = new UserCoupons();
            userCoupon.setUserId(userId.intValue());
            userCoupon.setCouponId(defaultCouponId);
            userCoupon.setStatus(1); // 1表示未使用
            userCoupon.setCreatedAt(new Date());

            userCouponsMapper.insert(userCoupon);

            // 5. 缓存到Redis（按指定格式）
            try {
                couponCacheUtil.addCouponToUserCache(userId, coupon, 6);
                log.info("新用户 {} 注册成功，已自动发放优惠券，ID: {}", userId, defaultCouponId);
            } catch (Exception e) {
                log.error("为新用户 {} 缓存优惠券失败: {}", userId, e.getMessage(), e);
                // 缓存失败不影响主流程
            }

            // 6. 记录操作日志
            String logDescription = String.format("新用户注册发放优惠券：%s", coupon.getTitle());
            adminLogService.saveLog(null, "system", "优惠券管理", "新用户发放", logDescription,
                "SYSTEM", "/system/new-user-coupon", userId.toString(),
                "发放成功", 1, null, "127.0.0.1", "System", 0L);

            return Result.success("新用户优惠券发放成功");

        } catch (Exception e) {
            log.error("为新用户 {} 发放优惠券失败: {}", userId, e.getMessage(), e);
            return Result.error("发放失败：" + e.getMessage());
        }
    }
}
